//! Copyright 2012 Virtium Technology, Inc.
//! All rights reserved
//!
#include "Reader.h"
#include "BoardHardware.h"
#include "Counter.h"
#include "StrLib.h"


#if defined (__FW_BUILD__)
extern "C"  {
#include "stm32f10x.h"

volatile U8  s_ClkFlag = 0;
volatile U8  s_DataCount = 0;
volatile U8  s_BitCount = 0;
volatile U8  s_MagStart[2] = {0,0};
volatile U8  s_Magstripe[WEIGAND_BITS_LENGTH];
volatile U32 s_CardData = 0;


    void EXTI2_IRQHandler(void)
    {
        if(EXTI_GetITStatus(EXTI_Line2) != RESET)
        {
            ++s_BitCount;
            s_ClkFlag = 1;

            /* Clear the  EXTI line 0 pending bit */
            EXTI_ClearITPendingBit(EXTI_Line2);
        }
    }

    void EXTI3_IRQHandler(void)
    {
        if(EXTI_GetITStatus(EXTI_Line3) != RESET)
        {
            if (WEIGAND_BITS_LENGTH > s_BitCount) s_Magstripe[s_BitCount] = 1; 
            ++s_BitCount;
            s_ClkFlag = 1;

            /* Clear the  EXTI line 0 pending bit */
            EXTI_ClearITPendingBit(EXTI_Line3);
        }
    }
}
#else
U8  cReader::s_ClkFlag;
U8  cReader::s_BitCount;
U8  cReader::s_Magstripe[WEIGAND_BITS_LENGTH];
U32 cReader::s_CardData;
#endif

bool cReader::s_NewCardFlag;
cSysTick cReader::s_CardTimeout;

void cReader::InitReset()
{
#if defined (__FW_BUILD__)
    EXTI_InitTypeDef   EXTI_InitStructure;
    GPIO_InitTypeDef   GPIO_InitStructure;
    NVIC_InitTypeDef   NVIC_InitStructure;

    /* Enable GPIOA clock */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

    /* Configure PA.02 & PA.03 pin as input floating */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    /* Enable AFIO clock */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);

    /* Connect EXTI2 Line to PB.03 pin */
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource2);

    /* Configure EXTI2 line */
    EXTI_InitStructure.EXTI_Line = EXTI_Line2;
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_Init(&EXTI_InitStructure);

    /* Enable and set EXTI2 Interrupt to the lowest priority */
    NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);


    /* Connect EXTI3 Line to PB.03 pin */
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource3);

    /* Configure EXTI3 line */
    EXTI_InitStructure.EXTI_Line = EXTI_Line3;
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_Init(&EXTI_InitStructure);

    /* Enable and set EXTI3 Interrupt to the lowest priority */
    NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
#endif

    s_NewCardFlag = false;
    s_CardTimeout.SetTimeout(10);
    CleanUpCardDataBuffer();
}


U32 cReader::GetNewCard()
{
    if (true == s_NewCardFlag)
    {
        s_NewCardFlag = false;
        return (s_CardData);
    }
    return (0);
}


void cReader::CleanUpCardDataBuffer()
{
    for (U8 i=0; i<WEIGAND_BITS_LENGTH; i++)
    {
        s_Magstripe[i] = 0;
    }
}

U32 cReader::DecodeWeigand()
{
    U32 cardData = 0;
    for (U8 i=1; i<(WEIGAND_BITS_LENGTH-1); i++)
    {
        cardData <<= 1;
        if ( 1 == s_Magstripe[i])
        {
            cardData |= 1;
        }
    }
    return (cardData);
}

void cReader::RunOne()
{
    if (WEIGAND_BITS_LENGTH == s_BitCount)
    {
        s_BitCount = 0;
        s_CardData = DecodeWeigand();
        CleanUpCardDataBuffer();
        s_NewCardFlag = true;
    }
    if (1 == s_ClkFlag)
    {
        s_ClkFlag = 0;
        s_CardTimeout.ResetTimeBase();
    }
    if (0 < s_BitCount)
    {
        if (true == s_CardTimeout.CheckTimeOut())
        {
            s_BitCount = 0;
            CleanUpCardDataBuffer();
        }
    }
    //if ((GPIOA->IDR & (1<<3))==0) cCounter::SetLedRed(true); else cCounter::SetLedRed(true);
}

